package com.zhao.dota.controller;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import com.zhao.dota.bo.AuthenticateUser;
import com.zhao.dota.exception.MatchException;
import com.zhao.dota.model.DotaMatch;
import com.zhao.dota.processor.QiniuProcessor;
import com.zhao.dota.security.SecurityUtil;
import com.zhao.dota.service.ImportMatchService;
import com.zhao.dota.service.MatchService;
import com.zhao.dota.struct.Chunk;
import com.zhao.dota.struct.Result;
import com.zhao.dota.util.NioUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/import")
@Slf4j
public class ImportController {

    @Resource
    private ImportMatchService importMatchService;
    @Resource
    private QiniuProcessor qiniuProcessor;
    @Resource
    private MatchService matchService;

    @Value("${server.tomcat.basedir}")
    private String tempPath;

    @PostMapping("/")
    public Result<Void> importMatch(MultipartFile multipartFile) {
        String filename = UUID.randomUUID().toString();
        File file = new File(getFinalFilename(filename));
        try {
            FileUtil.writeFromStream(multipartFile.getInputStream(), file);
            importMatchService.importMatch(file);
        } catch (IOException ignore) {
        } catch (MatchException e) {
            return Result.error(e.getMessage());
        } finally {
            if (file.exists()) {
                file.delete();
            }
        }
        return Result.success();
    }

    @GetMapping("/chunkUpload")
    public Result<Void> testChunkUpload(MultipartFile file, Chunk chunk) {
        boolean exists = new File(getFinalFilename(getFilename(chunk))).exists();
        if (chunk.getTotalChunks() > 1) {
            exists |= new File(getChunkName(chunk, chunk.getChunkNumber())).exists();
        }
        return Result.complete(exists);
    }

    private String getChunkName(Chunk chunk, int chunkNumber) {
        return tempPath + "/chunks/" + chunk.getIdentifier() + "_" + chunkNumber;
    }

    private String getFinalFilename(String filename) {
        return tempPath + "/" + filename;
    }

    @PostMapping("/chunkUpload")
    public Result<Void> chunkUpload(MultipartFile file, Chunk chunk) {
        boolean success;
        try {
            if (chunk.getTotalChunks() == 1) {
                success = upload(file, chunk);
            } else {
                success = NioUtil.upload(getChunkName(chunk, chunk.getChunkNumber()),
                        file.getInputStream(), chunk.getCurrentChunkSize());
                if (success && chunk.getTotalChunks() == chunk.getChunkNumber()) {
                    File merge = merge(chunk);
                    importMatchService.importMatch(merge);
                }
            }
            return Result.complete(success);
        } catch (IOException e) {
            log.error(String.format("上传文件失败， data: [%s]", JSON.toJSON(chunk)), e);
            return Result.error();
        }
    }

    private boolean upload(MultipartFile file, Chunk chunk) throws IOException {
        return NioUtil.upload(getFinalFilename(getFilename(chunk)),
                file.getInputStream(), chunk.getCurrentChunkSize());
    }

    private String getFilename(Chunk chunk) {
        String ext = FileUtil.extName(chunk.getFilename());
        String filename = chunk.getIdentifier();
        if (StringUtils.hasText(ext)) {
            filename += "." + ext;
        }
        return filename;
    }

    private File merge(Chunk chunk) {
        File file = new File(getFinalFilename(getFilename(chunk)));
        if (file.exists()) {
            file.delete();
        }
        try (FileOutputStream fileOutputStream = new FileOutputStream(file);
             FileChannel outChannel = fileOutputStream.getChannel()) {
            for (int i = 1; i < chunk.getTotalChunks() + 1; i++) {
                File inFile = new File(getChunkName(chunk, i));
                FileChannel inChannel = new FileInputStream(inFile).getChannel();
                inChannel.transferTo(0, inChannel.size(), outChannel);
                inFile.delete();
            }
        } catch (IOException e) {
            file.delete();
            log.error("合并文件失败", e);
        }
        return file;
    }

    @GetMapping("/reParse")
    public Result<List<Long>> reParse(Integer[] id) {
        List<Long> ids = Arrays.stream(id).map(i -> matchService.getById(i).getMatchId()).collect(Collectors.toList());
        try {
            importMatchService.parseReply(ids);
        } catch (IOException e) {
            log.error("解析录像文件失败, matchId: " + ids, e);
        }
        return Result.success();
    }

    @GetMapping("/qiniuToken")
    public Result<String> qiniuToken(String filename) {
        boolean b = qiniuProcessor.replyExists(filename);
        if (!b) {
            return Result.success(qiniuProcessor.uploadToken(filename));
        }
        return Result.error("文件已存在");
    }

    @GetMapping("/uploadQiniuSuccess")
    public Result<Void> uploadQiniuSuccess(String filename) {
        String matchId = filename.substring(0, filename.indexOf(".dem"));
        importMatchService.importMatch(Long.parseLong(matchId));
        return Result.success();
    }

}
